iT邦幫忙

2025 iThome 鐵人賽

DAY 6
0
佛心分享-IT 人自學之術

30 天從 Python 轉職場 C# 新手入門系列 第 6

Day6-C# 的函式(方法)與參數

  • 分享至 

  • xImage
  •  

前言

昨天學習完了常用的 if 判斷式跟迴圈的寫法以及用法,今天要進入函式的定義與使用方法。隨著程式越寫越大,常常會有某些程式碼需要被重複使用。這時候就需要把程式拆分成一個個「函式」(在 C# 裡稱為方法 Method)。使用函式能讓程式碼更乾淨、易讀、也更好維護。


📌Methods 的基本概念

Method,就是一段程式碼區塊,裡面包含一系列要執行的敘述。當程式呼叫 (call) 這個方法時,方法內的程式碼才會執行,並且可以傳入必要的參數 (arguments)。在 C# 中,每一個指令都是在某個方法內被執行的。


📌Method signatures

一個Method的宣告包含以下幾個部分:

  1. 存取修飾詞 (Access level) → 例如 public 或 private,預設是 private。
  2. 選用的修飾詞 (Modifiers) → 例如 abstract、sealed。
  3. 回傳值 (Return type) → 方法要回傳的資料型別,若沒有回傳則用 void。
  4. 方法名稱 (Method name) → 方法的名稱。
  5. 參數 (Parameters) → 包在小括號 () 中,多個參數以逗號分隔;若是空的括號 (),代表沒有參數。
    ➡️ 以上這些組合起來,就是方法簽章 (method signature)。

來看一段範例程式碼:

namespace MotorCycleExample
{
    abstract class Motorcycle
    {
        // 任何人都能呼叫
        public void StartEngine() { /* 方法內容 */ }

        // 只有衍生類別 (繼承者) 可以呼叫
        protected void AddGas(int gallons) { /* 方法內容 */ }

        // 衍生類別可以覆寫 (override) 這個方法
        public virtual int Drive(int miles, int speed) 
        { 
            /* 方法內容 */ 
            return 1; 
        }

        // 方法多載 (overloading):同名方法但參數不同
        public virtual int Drive(TimeSpan time, int speed) 
        { 
            /* 方法內容 */ 
            return 0; 
        }

        // 抽象方法:強制衍生類別必須實作
        public abstract double GetTopSpeed();
    }
}

在這段程式碼內的一些重點整理如下:

  1. Drive(int miles, int speed) 與 Drive(TimeSpan time, int speed) 名稱相同,但參數型別不同 → 編譯器會根據呼叫時傳入的參數來決定執行哪一個方法。
  2. public → 任何地方都能呼叫。protected → 只能在該類別及其子類別中呼叫。
  3. virtual 可以在子類別中使用 override 重新定義。
  4. abstract 沒有實作內容,子類別 必須實作。

Method invocation(調用)

在 C# 裡,方法 (method) 有兩種形式:

  1. 實例方法 (Instance method):必須先建立物件 (instantiate an object) 才能呼叫。它會操作該物件本身以及它的資料。
  2. 靜態方法 (Static method):透過「類別名稱」來呼叫,不需要建立物件。它不會操作物件的資料,而是屬於類別本身。如果用物件去呼叫靜態方法,會造成編譯錯誤。

在呼叫時會根據 Instance method 以及 Static method 有不同的呼叫方式,如果是 實例方法 → 使用 物件名稱.方法名稱(參數)。如果是 靜態方法 → 使用 類別名稱.方法名稱(參數)。括號裡的內容就是 引數 (arguments),多個引數用逗號分隔。而其中 Method 裡面又分兩種,參數 (Parameters) 與引數 (Arguments)。參數 (parameter) → 在方法定義裡指定的名稱與型別。引數 (argument) → 呼叫方法時傳入的實際值。引數必須與參數型別相容,但引數名稱不用跟參數名稱相同。

範例 1:靜態方法(Static method)呼叫

public static class SquareExample
{
    public static void Main()
    {
        // Call with an int variable.
        int num = 4;
        int productA = Square(num);

        // Call with an integer literal.
        int productB = Square(12);

        // Call with an expression that evaluates to int.
        int productC = Square(productA * 3);
    }

    static int Square(int i)
    {
        // Store input argument in a local variable.
        int input = i;
        return input * input;
    }
}

這個類別 SquareExample 定義了一個靜態 Square 函式,Main 在程式啟動時呼叫 Square 三次,分別傳入變數、常數與運算式,計算平方並把結果存到三個 product 變數中。

範例 2:位置引數 (Positional arguments)

最常見的呼叫方式是 位置引數,就是按照參數的順序一一對應。

namespace MotorCycleExample
{
    abstract class Motorcycle
    {
        // Anyone can call this.
        public void StartEngine() {/* Method statements here */ }

        // Only derived classes can call this.
        public void AddGas(int gallons) { /* Method statements here */ }

        // Derived classes can override the base class implementation.
        public virtual int Drive(int miles, int speed) { /* Method statements here */ return 1; }

        // Derived classes can override the base class implementation.
        public virtual int Drive(TimeSpan time, int speed) { /* Method statements here */ return 0; }

        // Derived classes must implement this.
        public abstract double GetTopSpeed();
    }
class TestMotorcycle : Motorcycle
{
    public override double GetTopSpeed() => 108.4;

    static void Main()
    {
        var moto = new TestMotorcycle();

        moto.StartEngine();
        moto.AddGas(15);
        _ = moto.Drive(5, 20);
        double speed = moto.GetTopSpeed();
        Console.WriteLine($"My top speed is {speed}");
    }
}
}

繼承了前面的 Motorcycle ,調用了前面的面的參數,執行後的結果會得到->My top speed is 108.4

範例 3:具名引數 (Named arguments)

也可以用 具名引數,直接指定參數名稱:

namespace MotorCycleExample
{
    abstract class Motorcycle
    {
        // Anyone can call this.
        public void StartEngine() {/* Method statements here */ }

        // Only derived classes can call this.
        public void AddGas(int gallons) { /* Method statements here */ }

        // Derived classes can override the base class implementation.
        public virtual int Drive(int miles, int speed) { /* Method statements here */ return 1; }

        // Derived classes can override the base class implementation.
        public virtual int Drive(TimeSpan time, int speed) { /* Method statements here */ return 0; }

        // Derived classes must implement this.
        public abstract double GetTopSpeed();
    }

    class TestMotorcycle : Motorcycle
    {
        public override int Drive(int miles, int speed) =>
            (int)Math.Round((double)miles / speed, 0);

        public override double GetTopSpeed() => 108.4;

        static void Main()
        {
            var moto = new TestMotorcycle();
            moto.StartEngine();
            moto.AddGas(15);
            int travelTime = moto.Drive(speed: 60, miles: 170);
            Console.WriteLine($"Travel time: approx. {travelTime} hours");
        }
    }
}

得到的結果為->Travel time: approx. 3 hours
與上一個範例不同的在於其優點,順序可以不同,只要有把參數名稱寫清楚。


今日小心得

今天所學習的內容對我來說稍微有些困難,感覺還要再花點時間消化,而且也沒達到預期的進度,所以明天會繼續把這個部分給學習完畢!今天的參考資料


上一篇
Day5-C# 的流程控制
系列文
30 天從 Python 轉職場 C# 新手入門6
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言